决策树

与SVM一样,决策树也是一种多功能的机器学习算法,

在本问中,我们将

决策树训练和可视化

要理解决策树,那就让我们构建一个决策树,看看它是怎么做出预测的。 以下代码在鸢尾花数据集(见第4章)上训练了一个DecisionTreeClassifier:

要可视化训练好的决策树,你可以通过使用export_graphviz()方法输出一个命名为iris_tree.dot的图形定义文件:

然后,你可以使用graphviz包中的dot命令行工具将这个.dot文件转换为各种格式,例如PDF或PNG。下面这条命令行可以将.dot文件转换为.png图像文件:

你的第一个决策树长这样 iris_tree

预测

让我们来看看图中表示的决策树是如何做出预测的。

决策树的特质之一就是,它们需要的数据准备工作非常少。特别的一点是,它们根本不需要进行特征缩放或集中

  1. 节点的samples属性统计它应用的训练实例数量。例如,有100个训练实例的花瓣长度大于2.45厘米(深度1,位于右侧),其中54个花瓣宽度小于1.75厘米(深度2,位于左侧)。

  2. 节点的value属性说明了该节点上每个类别的训练实例数量:例如,右下角节点应用在0个Setosa鸢尾花,1个Versicolor鸢尾花和45个Virginica鸢尾花实例上。

  3. 最后,节点的gini属性测量它的不纯度:如果节点应用的所有训练实例都属于同一个类别,那么这个节点就是“纯”的(gini = 0)。 例如,深度1的左侧节点仅引用于Setosa鸢尾花训练实例,所以它是纯的,并且特德gini值为0。

公式说明了第i个节点的gini值$G_i$的计算方法。 例如,深度2的左侧节点的gini值等于

 $ 1 - (0/54)^2 - (49/54)^2 - (5/54)^2≈0.168$。 稍后我们将讨论另一种不纯度的计算方法

基尼不纯度

$G_{i}=1-\sum_{k=1}^{n} p_{i, k}^{2}$

公式中,$p_{i,k}$是在第i个节点上,类别为k的训练实例占比。

Scikit-Learn使用的是CART算法,该算法只能生成二叉树:非叶节点永远只有两个子节点(即问题答案只有是/否)。但是,其他算法,比如ID3生成的决策树,它的节点可以拥有两个以上的子节点。 图6-2显示了决策树的决策边界。

模型解读:白盒与黑盒

如你所看到的,决策树是非常直观的,它们的决策也很容易解释。 这种模型通常被称为白盒模型。 与之相反的,正如我们稍后将要看到的,随机森林或神经网络通常被认为是黑盒模型。它们能够做出很好的预测,你也可以轻松检查它们做出这些预测时进行的计算;但是,通常很难用简单的术语来解释它们为什么做出这样的预测。例如,如果一个神经网络说某个人出现在一张图片上,很难知道它实际上是基于什么做出这样的预测:是模型识别出了这个人的眼睛?她的嘴巴?她的鼻子?她的鞋子?甚至是她坐的沙发?相反,决策树提供了简单好用的分类规则,如果需要的话,甚至可以手动应用这些规则(例如,花的分类)。

估算类别概率

决策树也可以估计某个实例属于特定类别 k 的概率:首先,跟随决策树找到该实例的叶节点,然后返回该节点中类别 k 的训练实例比例。 例如,如果你发现了一朵花,它的花瓣长5厘米,宽1.5厘米。 相应的叶节点是深度2的左侧节点,因此决策树输出如下概率:

当然,如果你要求它预测类别,它应该输出Versicolor鸢尾花(类别1),因为它的概率最高。让我们来检查一下:

完美!注意,在图6-2的右下角矩形中,任意点的估算概率都是相同的--比如,如果花瓣长6厘米,宽1.5厘米(虽然看起来在这种情况下,最可能是Virginica鸢尾花)。

CART训练算法

Scikit-Learn使用分类与回归树(Classification And Regression Tree-CART简称(CART))算法来训练决策树(也叫做“生长”树)。 想法非常简单: 首先使用单个特征 k 和阈值 $t_k$ (例如,“花瓣长度≤2.45cm”)将训练集分成两个子集。 k 和 $t_k$怎么选择呢呢?答案是产生出最纯子集(按其大小加权)的k 和 $t_k$就是经算法搜索确定的$(k,t_k)$ 。算法尝试最小化的成本函数为公式6-2:

公式6-2

$J\left(k, t_{k}\right)=\frac{m_{\mathrm{left}}}{m} G_{\mathrm{left}}+\frac{m_{\mathrm{right}}}{m} G_{\mathrm{right}}$

公式6-2中

如你所见,CART算法是一种贪婪算法:它贪婪地从顶层开始搜索最佳分裂,然后在每层都重复这个过程。 几层分裂后,它并不会检查这个分裂的不纯度是否为可能的最低值。 贪心算法通常会产生一个相当不错的解但它不能保证是最优解

而不幸的是,寻找最佳树是一个已知的NP完全问题:需要$O(exp(m))$时间,所以即使对于相当小的训练集,问题也很棘手。这就是为什么我们必须接受一个“合理的不错的”的解。

计算复杂度

进行预测需要从根到叶遍历决策树。通常来说,决策树大致平衡,因此遍历决策树需要经过大约$O(log_2(m))$个节点。因为每个节点仅需要检查一个特征值,所以总体预测复杂度也只是$O(log_2(m))$,与特征数量无关。 因此,即使是处理大型训练集,预测也非常快。

但是,训练时在每一个节点,算法都需要在所有样本上比较所有特征(如果设置了max_features会少一点)。 这导致训练的复杂度为$O(n×m log(m))。

基尼不纯度与信息熵

默认情况下,使用基尼不纯度来进行测量,但是你可以通过将标准超参数“criterion”设置为“entropy”来选择信息熵作为不纯度的测量方式。熵的概念起源于热力学,是一种分子混乱程度的度量: 如果分子保持静止或者有序状态,则熵接近于零。 后来这个概念传播到各种领域,其中包括香农的信息理论,它测量的是一条消息的平均信息内容:如果所有的消息都相同,则熵为零。 在机器学习中,它也经常被用作一种不纯度的测量方式:如果一个集合只包含一个类别的实例,集合的熵为零。 下列公式显示了第i个节点的熵值的计算方式。 例如,图6-1中的深度2的左侧节点的熵值等于$-\frac{49}{54}log(\frac{49}{54})-\frac{5}{54}log(\frac{5}{54})≈0.31$。

$H_{i}=-\sum_{k=1 \atop p_{i, k} \neq 0}^{n} p_{i, k} \log _{2}\left(p_{i, k}\right)$

那么你到底应该使用基尼不纯度还是信息熵呢? 其实,大多数情况下,它们之间没有什么大的不同:它们产生的树都很类似。基尼不纯度的计算速度稍微快一点,因此它是一个不错的默认选择。 它们不同在于,基尼不纯度倾向于从书中分裂出最常见的类别,而信息熵则倾向于生成更平衡的树。

正则化超参数

决策树很少对训练数据做出的假设(比如线性模型就正好相反,它显然假设数据是线性的)。如果不加以限制,树结构将跟随训练集变化,严密拟合,并且很可能过度拟合。 这种模型通常被称为非参数模型,这不是它不包含任何参数(它通常有很多),而是指训练之前没有确定参数的向量,所以模型结构可以自由地贴近数据。 相比之下,诸如线性模型的参数模型则有预先设定好的的一部分参数,因此其自由度受到限制,从而降低了过度拟合的风险(但增加了拟合不足的风险)。

为了避免过度拟合,你需要在训练期间限制决策树的自由度。 如你所知,这被称为正则化。正则化超参数的选择取决于所使用的算法,但通常你至少可以限制决策树的最大深度。 在Scikit-Learn中,这由超参数max_depth控制(默认值为None,意味着无限制)。减少max_depth可以使模型正则化,从而降低过度拟合的风险

DecisionTreeClassifier类还有一些其他的参数,同样可以限制决策树的形状:

还可以先在没有限制的情况下训练决策树,然后修剪(删除)不必要的节点。如果一个节点的子节点都是叶节点,这个节点可以被认为是不必要的,除非它所表示的纯度提升由衷的统计意义。标准统计检验,例如$χ^2$ 检验,是用来估算“提升纯粹是偶然结果”(被称为虚假设)的概率。如果这个概率(称之为p值)高于一个给定阈值(通常为5%,由超参数控制),那么该节点可以被认为是不必要的,其子节点可以被删除。直到所有不必要的节点都被删除,剪枝过程结束。

上图显示了在moons datasets (在第5章介绍)上训练的两个决策树。在左侧,使用默认超参数(即没有限制)训练决策树,在右侧,使用min_samples_leaf = 4训练决策树。很明显,左边的模型是过拟合的,右边的模型可能会泛化得更好。

回归

决策树还能够执行回归任务。让我们使用Scikit-Learn的DecisionTreeRegressor构建一个回归树,在一个有噪声的二次数据集上训练它,其中max_depth = 2

你的第二个决策树长这样 image-20200721092447379

这棵树看起来与你之前构建的分类树非常相似。主要区别在于,每个节点上不再是预测一个类别,而是预测一个值。例如,如果你想要对$x_1 = 0.6$的新实例进行预测。 那么从根节点开始遍历树,最终到达预测值predicts value = 0.1106 的叶节点。 这个预测结果其实就是与这个叶节点相关联的110个训练实例的平均目标值。 在这110个实例上,预测产生的均方误差(MSE)等于0.0151。

在图6-5的左侧显示了模型的预测。如果设置max_depth = 3,将会获得如右侧所示的预测。注意看,每个区域的预测值始终是该区域中实例的平均目标值。算法分裂每个区域的方法,就是使最多的训练实例尽可能接近这个预测值。

CART算法的工作原理与前面介绍的大致相同,唯一不同在于,它分裂训练集的方式不是最小化不纯度,而是最小化MSE。公式6-4显示了算法尝试最小化的成本函数。

$J\left(k, t_{k}\right)=\frac{m_{\mathrm{left}}}{m} \mathrm{MSE}_{\mathrm{left}}+\frac{m_{\mathrm{right}}}{m} \mathrm{MSE}_{\mathrm{right}}$

就像分类任务一样,决策树在处理回归任务时也很容易过度拟合。如果没有任何正则化(即使用默认的超参数),你将获得如图6-6左侧所示的预测结果。 这显然对训练集严重过度拟合。只需要设置min_samples_leaf = 10,就能够得到一个看起来合理得多的模型,如图6-6右侧所示。

不稳定性

希望现在,你已经确信了选择决策树有充足的理由:它们很容易理解和解释,使用简单,功能多样,功能全面并且十分强大。但是它们确实也有一些限制。

  1. 首先,正如你可能已经注意到的,决策树青睐正交的决策边界(所有分裂都与轴线垂直),这导致它们对训练集的旋转非常敏感。例如,图6-7显示了一个简单的线性可分离数据集:

    • 在左侧,决策树可以轻分裂,
    • 在右侧,数据集旋转45°后,决策边界看起来产生了不必要的卷曲。

    尽管两个决策树看起来都完美地拟合训练集,但是右侧的模型很可能泛化不佳。 限制这种问题的方法之一是使用PCA(参见第8章),让训练数据定位在一个更好的方向上。

  1. 更概括地说,决策树的主要问题是它们对训练数据中的微小变化非常敏感。例如,如果你只是从鸢尾花训练集中移除最宽的Versicolor鸢尾花(花瓣长4.8厘米,宽1.8厘米),然后重新训练一个新的决策树,你可能得到如图6-8所示的模型。这跟之前6-2的决策树看起来完全不同。事实上,由于Scikit-Learn使用的训练算法是随机的,即使在相同的训练数据上,你也可能得到完全不同的模型(除非你对random_state超参数进行了设置)。